#include <iostream>
#include <string>
#include <memory>
using namespace std;

#include "IniFile.h"


int main ()
{
	inilib::IniInfo * format = new inilib::IniInfo();

	try
	{
		format->AddSection( "Sekce 1", inilib::MANDATORY );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeString( "polozka1", inilib::NONMANDATORY, inilib::SINGLE_VALUE ) );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeString( "polozka2", inilib::NONMANDATORY, inilib::MULTIPLE_VALUES ) );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeNumeric< int >(
			"integers", inilib::MANDATORY, inilib::MULTIPLE_VALUES, 0, -100, 100, ':' ) );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeNumeric< float >( "floats", inilib::MANDATORY, inilib::MULTIPLE_VALUES ) );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeNumeric< double >( "doubles", inilib::MANDATORY, inilib::MULTIPLE_VALUES ) );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeBool( "booleans", inilib::MANDATORY, inilib::MULTIPLE_VALUES, false, '#' ) );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeNumeric< float >( "rac_cislo", inilib::MANDATORY, inilib::SINGLE_VALUE ) );
//		format->AddOption( "Sekce 3",
//			new inilib::OptionTypeNumeric< float >( "rac_cislo", inilib::MANDATORY, inilib::SINGLE_VALUE ) );

		vector< string > vec;
		vec.push_back( "auto" );
		vec.push_back( "kolo" );
		vec.push_back( "autobus" );
		format->AddOption( "Sekce 1",
			new inilib::OptionTypeEnum( "enum", vec, inilib::NONMANDATORY, inilib::MULTIPLE_VALUES ) );

		format->AddSection( "Sekce 2", inilib::NONMANDATORY );
		format->AddOption( "Sekce 2",
			new inilib::OptionTypeNumeric< int >( "s2_cislo", inilib::NONMANDATORY, inilib::SINGLE_VALUE, 101 ) );

		format->AddSection( "Sekce 5", inilib::NONMANDATORY );
		format->AddOption( "Sekce 5",
			new inilib::OptionTypeString( "s5", inilib::MANDATORY, inilib::MULTIPLE_VALUES ) );

		format->AddSection( "Sekce 6", inilib::NONMANDATORY );
		format->AddOption( "Sekce 6",
			new inilib::OptionTypeString( "s6", inilib::MANDATORY, inilib::MULTIPLE_VALUES ) );

		format->AddSection( "Sekce 7", inilib::NONMANDATORY );
		format->AddOption( "Sekce 7",
			new inilib::OptionTypeString( "s7", inilib::MANDATORY, inilib::MULTIPLE_VALUES ) );
	}
	catch ( const inilib::ExceptionIniLib & e )
	{
		cout << "Exception: " << e.GetInfo() << "\n";
	}

	std::string fileData =
		"   \n"
		"   \n"
		"   ;dulezity komentar\n"
		"		;pres vice radku!\n"
//		"polozka = hodnota\n"
		"  [Sekce 1]   ; jo, tohle je uzasna sekce\n"
		"; komentar k hodnote1\n"
		"polozka1 = hodnota1\n"
		"polozka2 = hodnota1,hodnota2,hodnota3 ; komentare k hodnote dva\n"
		"integers = +10 : -0xF : +25 : -0p111 : +017 ; toto jsou cela cisla!\n"
		"; a toto nejsou cela cisla\n"
		"; protoze jsou desetinna\n"
		"floats = 3.14  , -124.45667356  ,   +4.1234565E+10  , 412.34565e10  , -1.1245864E-6\n"
		"doubles = 3.14 , -124.45667356 , +4.1234565E+10  , 412.34565e10  , -1.1245864E-6\n"
		"booleans = 1# t# y# on  # yes   #   enabled # 0 # f # n # off # no # disabled ;booleany jsou cool\n"
		"rac_cislo = 1.2345\n"
		"option 1 \\ \\  =  \\ value 2\\ \\ \\ \\ \n"
		"enum = auto, kolo, kolo\n"
//		"[Sekce 2]\n"
		"[Sekce 5]\n"
		"s5 = s5, ${Sekce 6#s6}\n"
		"\n"
		"[Sekce 6]\n"
		"s6 = s6, ${Sekce 7#s7}\n"
		"\n"
		"[Sekce 7]\n"
		"s7 = s7\n" //, ${Sekce 5#s5}\n"
		"\n"
	;

	try
	{
		unique_ptr< inilib::IniFile > ini( inilib::IniFile::Create( format, inilib::RELAXED, fileData ) );

		// ----------------------------------------------------------
		// Get test
		// ----------------------------------------------------------
		
		vector< string > s2 = ini->GetValues< string >( "Sekce 1", "polozka2" );
		for ( size_t i = 0; i < s2.size(); ++i )
		{
			cout << s2[ i ] << " ";
		}
		cout << "\n";

		auto integers = ini->GetValues< int >( "Sekce 1", "integers" );
		for ( size_t i = 0; i < integers.size(); ++i )
		{
			cout << integers[ i ] << " ";
		}
		cout << "\n";

		auto floats = ini->GetValues< float >( "Sekce 1", "floats" );
		for ( size_t i = 0; i < floats.size(); ++i )
		{
			cout << floats[ i ] << " ";
		}
		cout << "\n";

		auto doubles = ini->GetValues< double >( "Sekce 1", "doubles" );
		for ( size_t i = 0; i < doubles.size(); ++i )
		{
			cout << doubles[ i ] << " ";
		}
		cout << "\n";

		auto booleans = ini->GetValues< bool >( "Sekce 1", "booleans" );
		for ( size_t i = 0; i < booleans.size(); ++i )
		{
			cout << booleans[ i ] << " ";
		}
		cout << "\n";

		auto option1 = ini->GetValue< string >( "Sekce 1", "option 1  " );
		cout << "\"" << option1 << "\"\n";

		auto enums = ini->GetValues< string >( "Sekce 1", "enum" );
		for ( size_t i = 0; i < enums.size(); ++i )
		{
			cout << enums[ i ] << " ";
		}
		cout << "\n";

		// ----------------------------------------------------------
		// Set test
		// ----------------------------------------------------------

		{
			string s1 = ini->GetValue< string >( "Sekce 1", "polozka1" );
			cout << s1 << "\n";
			ini->SetValue< string >( "Sekce 1", "polozka1", "pol" );
			s1 = ini->GetValue< string >( "Sekce 1", "polozka1" );
			cout << s1 << "\n";

			float f = ini->GetValue< float >( "Sekce 1", "rac_cislo" );
			cout << f << "\n";
			ini->SetValue< float >( "Sekce 1", "rac_cislo", 1.5f );
			f = ini->GetValue< float >( "Sekce 1", "rac_cislo" );
			cout << f << "\n";

			auto booleans = ini->GetValues< bool >( "Sekce 1", "booleans" );
			for ( size_t i = 0; i < booleans.size(); ++i )
			{
				cout << booleans[ i ] << " ";
			}
			cout << "\n";

			booleans.clear();
			booleans.push_back( true );
			booleans.push_back( false );
			booleans.push_back( true );
			ini->SetValues< bool >( "Sekce 1", "booleans", booleans );

			booleans = ini->GetValues< bool >( "Sekce 1", "booleans" );
			for ( size_t i = 0; i < booleans.size(); ++i )
			{
				cout << booleans[ i ] << " ";
			}
			cout << "\n";
		}

		int s2_cislo = ini->GetValue< int >( "Sekce 2", "s2_cislo" );
		cout << "s2_cislo: " << s2_cislo << "\n";

		string iniOut;
		ini->SaveTo( iniOut );
		cout << "-----------------------------------\n";
		cout << iniOut;

		// ----------------------------------------------------------
		// Reference test
		// ----------------------------------------------------------

		auto s5 = ini->GetValues< string >( "Sekce 5", "s5" );
		cout << "s5: ";
		for ( size_t i = 0; i < s5.size(); ++i )
			cout << s5[ i ] << " ";
		cout << "\n";

		auto s6 = ini->GetValues< string >( "Sekce 6", "s6" );
		cout << "s6: ";
		for ( size_t i = 0; i < s6.size(); ++i )
			cout << s6[ i ] << " ";
		cout << "\n";

		auto s7 = ini->GetValues< string >( "Sekce 7", "s7" );
		cout << "s7: ";
		for ( size_t i = 0; i < s7.size(); ++i )
			cout << s7[ i ] << " ";
		cout << "\n";

		/*
		// create cycle:
		ini->SetValue< string >( "Sekce 7", "s7", "${Sekce 5#s5}" );
		*/
	}
	catch ( const inilib::ExceptionIniLib & e )
	{
		cout << "Exception: " << e.GetInfo() << "\n";
	}

	return 0;
}